﻿using Mes.Domain.BoundedContext;
using AutoMapper;
using System.Linq.Expressions;
using Mes.Infrastructure.Data.BoundedContext.Extensions;
using Microsoft.EntityFrameworkCore;
using System.Data;
using Newtonsoft.Json;
using Mes.Application.Common;
using Mes.Application.Common.Resource;
using Mes.Application.DTO.Inputs.MasterData;
using Mes.Application.DTO.Results.MasterData;
using Mes.Domain.BoundedContext.Entities.MasterData;
using Mes.Infrastructure.Data.BoundedContext.Repositories.MasterData;
using Mes.Domain.BoundedContext.Entities.WorkOrders;
using Mes.Infrastructure.Data.BoundedContext.Repositories.WorkOrders;

namespace Mes.Application.Services.MasterData
{
    public class ProductionUnitService : IProductionUnitService
    {
        private readonly IProductionUnitRepository _productionUnitRepository;
        private readonly IProductionUnitTypeRepository _productionUnitTypeRepository;
        private readonly IMapper _mapper;
        private TreeNode _tree;
        private readonly IJobExecRepository _jobExecRepository;
        public ProductionUnitService(IProductionUnitRepository productionUnitRepository, IMapper mapper, IProductionUnitTypeRepository productionUnitTypeRepository, IJobExecRepository jobExecRepository)
        {
            if (productionUnitRepository == null || mapper == null || productionUnitTypeRepository == null|| jobExecRepository==null)
            {
                throw new ArgumentNullException();
            }
            _productionUnitRepository = productionUnitRepository; //注入仓储类
            _mapper = mapper;
            _productionUnitTypeRepository = productionUnitTypeRepository;
            _jobExecRepository = jobExecRepository;
        }

        /// <summary>
        /// 新增生产单元
        /// </summary>
        /// <param name="productionUnitInput"></param>
        /// <returns></returns>
        /// <exception cref="CustomException"></exception>
        public async Task AddProductionUnitAsync(ProductionUnitInput productionUnitInput)
        {
            bool hasRoot = false;
            if (GetChildProductionUnit(0).Count != 0)
            {
                hasRoot = true;
            }

            if (!hasRoot && productionUnitInput.ParentProductionUnitId != 0)
            {
                throw new CustomException(Messages.RootNodeNotFound);
            }

            if (hasRoot && productionUnitInput.ParentProductionUnitId == 0)
            {
                throw new CustomException(Messages.RootNodeDuplication);
            }

            if (await _productionUnitRepository.ExistsAsync(x => x.ProductionUnitName == productionUnitInput.ProductionUnitName || x.ProductionUnitCode == productionUnitInput.ProductionUnitCode))
            {
                throw new CustomException(Messages.ProductionUnitExist);
            }

            var productionUnit = _mapper.Map<ProductionUnit>(productionUnitInput);
            if (productionUnit.ProductionUnitTypeId != 0)
            {
                var productionUnitType = QueryFieldValue(productionUnit.ProductionUnitTypeId);
                if (productionUnitType != null)
                {
                    productionUnit.ProductionUnitType = productionUnitType.Type;
                }
            }
            if (productionUnit.ParentProductionUnitId != 0)
            {
                var unit = GetProductionUnitAsyncById(productionUnit.ParentProductionUnitId);
                if (unit != null)
                {
                    productionUnit.ParentProductionUnit = unit.Result.ProductionUnitName;
                }
            }
            await _productionUnitRepository.AddAsync(productionUnit);
            int status = await _productionUnitRepository.SaveAsync();
            if (status <= 0)
            {
                throw new CustomException(Messages.SavingFailure);
            }
            //添加job_exec表记录
            var jobExec = new JobExec(productionUnit.Id);
            await _jobExecRepository.AddAsync(jobExec);
            int status1 = await _jobExecRepository.SaveAsync();
            if (status1 <= 0)
            {
                throw new CustomException(Messages.SavingFailure);
            }
        }

        /// <summary>
        /// 修改生产单元
        /// </summary>
        /// <param name="productionUnitUpdateInput"></param>
        /// <returns></returns>
        /// <exception cref="CustomException"></exception>
        public async Task UpdateProductionUnitAsync(ProductionUnitUpdateInput productionUnitUpdateInput)
        {
            var parent = GetChildProductionUnit(0);
            if (parent[0].Id == productionUnitUpdateInput.Id && productionUnitUpdateInput.ParentProductionUnitId != 0)
            {
                throw new CustomException(Messages.RootNodeParentCantBeEdited);
            }
            var productionUnit = await _productionUnitRepository.FindAsync(x => x.Id == productionUnitUpdateInput.Id);
            if (productionUnit == null)
            {
                throw new CustomException(Messages.ProductionUnitNotFound);
            }

            if (productionUnitUpdateInput.ProductionUnitTypeId != 0)
            {
                var productionUnitType = QueryFieldValue(productionUnitUpdateInput.ProductionUnitTypeId);
                if (productionUnitType != null)
                {
                    productionUnit.ProductionUnitType = productionUnitType.Type;
                }
            }
            else
            {
                productionUnit.ProductionUnitType = string.Empty;
            }

            if (productionUnitUpdateInput.ParentProductionUnitId != 0)
            {
                var unit = GetProductionUnitAsyncById(productionUnitUpdateInput.ParentProductionUnitId);
                if (unit != null)
                {
                    productionUnit.ParentProductionUnit = unit.Result.ProductionUnitName;
                }
            }
            else
            {
                productionUnit.ParentProductionUnit = string.Empty;
            }

            var childs = GetChildProductionUnit(productionUnitUpdateInput.Id);
            foreach (var child in childs)
            {
                child.ParentProductionUnit = productionUnitUpdateInput.ProductionUnitName;
            }

            productionUnit.ProductionUnitName = productionUnitUpdateInput.ProductionUnitName;
            productionUnit.ProductionUnitCode = productionUnitUpdateInput.ProductionUnitCode;
            productionUnit.ProductionUnitTypeId = productionUnitUpdateInput.ProductionUnitTypeId;
            productionUnit.ParentProductionUnitId = productionUnitUpdateInput.ParentProductionUnitId;
            productionUnit.Enabled = productionUnitUpdateInput.Enabled;
            productionUnit.UpdateTime = DateTime.Now;
            int status = await _productionUnitRepository.SaveAsync();
            if (status <= 0)
            {
                throw new CustomException(Messages.SavingFailure);
            }
        }

        /// <summary>
        /// 删除生产单元
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        /// <exception cref="CustomException"></exception>
        public async Task DeleteProductionUnitAsync(int[] ids)
        {
            HashSet<int> hashSet = new HashSet<int>();
            foreach (int id in ids)
            {
                AddChildId(hashSet, id);
                hashSet.Add(id);
            }

            Expression<Func<ProductionUnit, bool>> filter = x => hashSet.Contains(x.Id);
            if (filter == null)
            {
                throw new CustomException(Messages.ProductionUnitNotFound);
            }
            _productionUnitRepository.Delete(filter);
            //删除job_exec表记录
            _jobExecRepository.Delete(x => hashSet.Contains(x.Ent_Id));
            int status = await _productionUnitRepository.SaveAsync();
            if (status <= 0)
            {
                throw new CustomException(Messages.SavingFailure);
            }
        }

        /// <summary>
        /// 根据主键编号查询生产单元
        /// </summary>
        /// <param name="id"></param>
        /// <returns>ProductionUnitResult</returns>
        /// <exception cref="CustomException"></exception>
        public async Task<ProductionUnitResult> GetProductionUnitAsyncById(int id)
        {
            var productionUnit = await _productionUnitRepository.Query().Where(x => x.Id == id).FirstOrDefaultAsync();
            if (productionUnit == null)
            {
                throw new CustomException(Messages.ProductionUnitNotFound);
            }
            return _mapper.Map<ProductionUnitResult>(productionUnit);
        }

        /// <summary>
        /// 分页查询生产单元
        /// </summary>
        /// <param name="productionUnitPageInput"></param>
        /// <returns>PagedItemsData<ProductionUnitResult></returns>
        /// <exception cref="CustomException"></exception>
        public async Task<PagedItemsData<ProductionUnitResult>> GetProductionUnitAsync(ProductionUnitPageInput productionUnitPageInput)
        {
            Expression<Func<ProductionUnit, bool>> filter = x => true;
            if (!string.IsNullOrEmpty(productionUnitPageInput.ProductionUnitName))
            {
                filter = x => x.ProductionUnitName.Contains(productionUnitPageInput.ProductionUnitName);
            }
            var productionUnit = await _productionUnitRepository.Query().Where(filter).ToPagedAsync(productionUnitPageInput.PagedInput);
            if (productionUnit == null)
            {
                throw new CustomException(Messages.ProductionUnitNotFound);
            }
            return _mapper.Map<PagedItemsData<ProductionUnitResult>>(productionUnit);
        }

        /// <summary>
        /// 获取整棵生产单元树
        /// </summary>
        /// <returns>json树</returns>
        /// <exception cref="CustomException"></exception>
        public async Task<string> GetProductionUnitTreeAsync()
        {
            List<ProductionUnit> firstItem = GetChildProductionUnit(0);
            if (firstItem.Count == 0 || firstItem.ElementAt(0).ParentProductionUnitId != 0)
            {
                throw new CustomException(Messages.RootNodeNotFound);
            }
            TreeNode rootNode = new TreeNode();
            rootNode.name = firstItem.ElementAt(0).ProductionUnitName;
            rootNode.id = firstItem.ElementAt(0).Id;

            List<ProductionUnit> allItems = GetChildProductionUnit(-1);
            allItems.Remove(firstItem.ElementAt(0));
            _tree = BuildTree(allItems, rootNode);
            return JsonConvert.SerializeObject(_tree);
        }

        /// <summary>
        /// 获取所有孩子结点
        /// </summary>
        /// <param name="productionUnitChildsInput"></param>
        /// <returns>PagedItemsData<ProductionUnitResult></returns>
        /// <exception cref="CustomException"></exception>
        public async Task<PagedItemsData<ProductionUnitResult>> GetProductionUnitChildsAsync(ProductionUnitChildsInput productionUnitChildsInput)
        {
            Expression<Func<ProductionUnit, bool>> filter = x => true;
            if (productionUnitChildsInput.Id >= 0)
            {
                filter = x => x.ParentProductionUnitId == productionUnitChildsInput.Id;
            }
            var productionUnit = await _productionUnitRepository.Query().Where(filter).ToPagedAsync(productionUnitChildsInput.PagedInput);
            if (productionUnit == null)
            {
                throw new CustomException(Messages.ProductionUnitNotFound);
            }
            var result = _mapper.Map<PagedItemsData<ProductionUnitResult>>(productionUnit);
            return result;
        }

        private ProductionUnitType QueryFieldValue(int id)
        {
            return _productionUnitTypeRepository.Query().Where(x => x.Id == id).FirstOrDefault();
        }

        private List<ProductionUnit> GetChildProductionUnit(int parentId)
        {
            Expression<Func<ProductionUnit, bool>> filter = x => true;
            if (parentId != -1)
            {
                filter = x => x.ParentProductionUnitId == parentId;
            }
            var productionUnit = _productionUnitRepository.Query().Where(filter).ToArray();
            List<ProductionUnit> values = new List<ProductionUnit>();
            foreach (ProductionUnit unit in productionUnit)
            {
                values.Add(unit);
            }
            return values;
        }

        private TreeNode BuildTree(IList<ProductionUnit> productionUnitItems, TreeNode parentNode)
        {
            if (productionUnitItems.Count == 0)
            {
                return parentNode;
            }

            foreach (ProductionUnit productionUnit in productionUnitItems.ToList())
            {
                if (productionUnit.ParentProductionUnitId != parentNode.id)
                {
                    continue;
                }
                TreeNode node = new TreeNode();
                node.name = productionUnit.ProductionUnitName;
                node.id = productionUnit.Id;
                parentNode.AddChildren(node);
                productionUnitItems.Remove(productionUnit);
            }

            foreach (TreeNode childNode in parentNode.children)
            {
                BuildTree(productionUnitItems, childNode);
            }

            return parentNode;
        }

        private void AddChildId(HashSet<int> hashSet, int id)
        {
            List<ProductionUnit> childs = GetChildProductionUnit(id);
            if (childs.Count != 0)
            {
                foreach (ProductionUnit child in childs)
                {
                    hashSet.Add(child.Id);
                    AddChildId(hashSet, child.Id);
                }
            }
        }
    }
}
